#include "owm_management.h"
#include "memory_management.h"
#include "page_management.h"

#include "wish_queue.h"
#include "asyncpages.h"
#include <boost/unordered_map.hpp>
#include <string.h>
#include <misc.h>



typedef void * PtrType;
typedef struct  owm_wrdesc* owm_wrdesc_ptr;

struct owm_register_entry {
    owm_register_entry( void * _dest,
                        owm_wrdesc_ptr _owm_wrdesc,
                        size_t _size,
                        void * _tmp_buffer )
    : dest(_dest),
      owm_wrdesc( _owm_wrdesc ),

        size(_size),
        tmp_buffer(_tmp_buffer) {}

    void * dest;
    owm_wrdesc_ptr owm_wrdesc;
    size_t size;
    void * tmp_buffer;
};

typedef boost::unordered_multimap<PtrType, owm_register_entry> owm_map_t;
typedef std::pair<owm_map_t::iterator,owm_map_t::iterator> range;

static __thread owm_map_t * owm_map;


void dfrt_owm_tls_init() {
    owm_map = new owm_map_t();
}


void * dfrt_owm_malloc( size_t size ) {
    return dfrt_mem_malloc( size );
}

void dfrt_owm_free( void * ptr) {
    // TODO : debug_mode sanity checks ?

    dfrt_mem_free( ptr );
}


void * dfrt_owm_acquire(void *ptr,
                        size_t size,
                        struct owm_wrdesc *owm_wrdesc,
                        bool exclusive) {

    // TODO : make these sanity checks debug-only.
    if ( ptr == NULL || owm_wrdesc == NULL ) {
        FATAL( "NULL parameters passed.");
    }

    bool succeeded = async_request_page( ptr, size, exclusive);

    if (succeeded) {
        // Just register it as ok.
        owm_map->emplace( ptr, ptr, owm_wrdesc, size, (PtrType)NULL ); // NULL tmp buffer.
        return ptr;
    } else {
        // Acquire failed.
        // Fetching a copy.
        void * tmp = malloc( size );
        memcpy( tmp, ptr, size );

        // Register it as using a tmp buffer :
        owm_map->emplace( ptr, ptr, owm_wrdesc, size, (PtrType)tmp );

        return tmp;
    }
}

void dfrt_owm_release(void *ptr) {
    // Get the register entry :
    range r = owm_map->equal_range(ptr);

    if ( r.first == owm_map->end() ) {
        FATAL( "Releasing a non acquired OWM memory zone.");
    }

    owm_map_t::iterator next = r.first;
    next ++;


    owm_map_t::iterator it = r.first;
    // Check if there is any operation needed here :
    if ( it->second.tmp_buffer == NULL ) {
        // Then we just remove it.

        owm_map->erase( it );
        safe_release_page(ptr);
        return;
    }

    // schedule a wishlist element
    add_to_wishlist( it->second.dest, it->second.size,
                     it->second.owm_wrdesc->wrvec,
                     it->second.owm_wrdesc->nwrvec,
                     it->second.owm_wrdesc->decvec,
                     it->second.owm_wrdesc->ndecvec,
                     0, // Doesn't make sense to decrement OWM frame.
                     it->second.tmp_buffer ); // Where to get the data.

    // Now, we need to check page arrival and trigger commit.

    bool is_acquired = false;
    is_acquired = page_is_acquired(it->second.dest);


    if ( is_acquired ) {
        wishlist_commit_page(it->second.dest);
    } else {

    }





}
